﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AMStudio.Common;
using System.Text.RegularExpressions;
using Microsoft.Practices.EnterpriseLibrary.ExceptionHandling;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Logging;
using AMStudio.DelegateDispather;
using System.IO.Ports;
using System.Threading;

namespace AMStudio.Driver
{
    public class CameraDriverL : IAutomationDriver
    {
        protected ExceptionManager ExManager = EnterpriseLibraryContainer.Current.GetInstance<ExceptionManager>();

        private CameraConfigL myConfig = null;

        private DelegateDispather.IEventClient eventClient;
        public DelegateDispather.IEventClient EventClient
        {
            get { return eventClient; }
            set { eventClient = value; }
        }
        private CognexDriverL hardwaredriver;
        private bool alreadyinitialized = false;
        private IExecuteReader result = new ExecuteReader(false);
        private int intBeginRead = 0;

        private String hardwareName = "CAMERA";
        public String HardwareName
        {
            get { return hardwareName; }
            set { hardwareName = value; }
        }
        private String hardwareEvent = "CAMERA_RET";
        public String HardwareEvent
        {
            get { return hardwareEvent; }
            set { hardwareEvent = value; }
        }

        public void Initialize(IEventManager eventManager,CameraConfigL config)
        {
            myConfig = config;
            hardwaredriver = new CognexDriverL(config.IPAddress, config.TcpPort, config.User, config.Password, config.TcpPortS);
            hardwaredriver.OnDataReceived += new CognexDriverL.CameraDataReceivedHandler(hardwaredriver_OnDataReceived);
            hardwaredriver.OnConnectClosed += new CognexDriverL.CameraConnectClosedHandler(hardwaredriver_OnConnectClosed);
            hardwaredriver.OnConnected += new CognexDriverL.CameraConnectedHandler(hardwaredriver_OnConnected);
            eventClient = new EventClient(eventManager);
            this.hardwareEvent = config.HardwareEvent;
            this.hardwareName = config.HardwareName;
        }
        public virtual int ExecuteNonQuery(string command, params object[] parameters)
        {
            return -1;
        }

        private void OnNewCommand(string txCommand)
        {
            RaiseEvent("TRIGGER_RESULT", true, txCommand);
        }

        public virtual IExecuteReader ExecuteReader(string command, params object[] parameters)
        {
            _Signal_Command_Finished.Reset();
            _Received_Data = null;
            result.Success = false;
            try
            {
                switch (command)
                {
                    case "INIT":
                        #region Command "INIT"
                        {
                            if (!alreadyinitialized)
                            {
                                this.Initialize((IEventManager)parameters[0], (CameraConfigL)parameters[1]);
                                if (!hardwaredriver.Initialize())
                                {
                                    Logger.Write("System Error! (Can not connect the laser controller!)");
                                    hardwaredriver.Close();
                                }
                                else
                                {
                                    hardwaredriver.NewCommandEventHandler += OnNewCommand;
                                    result.Success=true;
                                    alreadyinitialized = true;
                                }
                            }
                        }
                        #endregion
                        break;
                    case "EXIT":
                        #region Command "DISCONNECT"
                        result.Success = true;
                        if (alreadyinitialized)
                        {
                            hardwaredriver.Close();
                            alreadyinitialized = false;
                        }
                        #endregion
                        break;
                    case "TRIGGER":
                        #region Command "TRIGGER"
                        {
                            if (alreadyinitialized)
                            {
                                _Current_Command = "TRIGGER";
                                hardwaredriver.ResetResult();
                                result.Success = SendCommandTrigger();
                                intBeginRead = Environment.TickCount & Int32.MaxValue;
                            }
                        }
                        #endregion
                        break;
                    case "TRIGGER_RESULT":
                        #region Command "TRIGGER_RESULT"
                        {
                            if (alreadyinitialized)
                            {
                                result.Success = hardwaredriver.WaitResult(0);
                                if (result.Success)
                                {
                                    if (hardwaredriver.Result == "1")
                                    {
                                        result.Result = "OK";
                                    }
                                    else
                                    {
                                        result.Result = "NG";
                                    }
                                }
                                else
                                {
                                    int intTickCount = Environment.TickCount & Int32.MaxValue;
                                    int intTimeTaken = intTickCount < intBeginRead ? Int32.MaxValue - intBeginRead + intTickCount : intTickCount - intBeginRead;

                                    if (intTimeTaken > 3000)
                                    {
                                        result.Result = "NG";
                                        result.Success = true;
                                    }
                                }
                            }
                            else
                            {
                                result.Result = "ERR";
                                result.Success = true;
                            }
                        }
                        #endregion
                        break;
                    case "SN_RESULT":
                        #region Command "SN_RESULT"
                        {
                            if (alreadyinitialized)
                            {
                                result.Success = SendCommandReadCellValue("C026");
                                if (result.Success)
                                {
                                    if (_Received_Data.Length >= 0 && _Received_Data[0] == "OK")
                                        result.Result = true;
                                    else if (_Received_Data.Length >= 0 && _Received_Data[0] == "NG")
                                        result.Result = false;
                                    if (_Received_Data.Length > 0)
                                    {
                                        RaiseEvent("SN_RESULT", true, _Received_Data[0]);
                                    }
                                    SendCommand("SSE025", "Response");
                                }
                                else
                                {
                                    result.Result = "ERR";
                                }
                            }
                            else
                            {
                                result.Result = "ERR";
                                result.Success = true;
                            }
                        }
                        #endregion
                        break;
                    case "ONLINE":
                        #region Command "ONLINE"
                        {
                            if (alreadyinitialized)
                            {
                                _Current_Command = "ONLINE";
                                result.Success = SendCommandOnline("1");
                            }
                        }
                        #endregion
                        break;
                    case "OFFLINE":
                        #region Command "OFFLINE"
                        {
                            if (alreadyinitialized)
                            {
                                _Current_Command = "OFFLINE";
                                result.Success = SendCommandOnline("0");
                            }
                        }
                        #endregion
                        break;
                    case "RESET":
                        #region Command "RESET"
                        {
                            if (alreadyinitialized)
                            {
                                _Current_Command = "RESET";
                                result.Success = SendCommandReset(parameters[0].ToString());
                            }
                        }
                        #endregion
                        break;
                    case "PRESET":
                        #region Command "RESET"
                        {
                            if (alreadyinitialized)
                            {
                                _Current_Command = "PRESET";
                                result.Success = SendCommandReset("0");
                            }
                        }
                        #endregion
                        break;
                    case "TRIGGER_STATUS":
                        #region Command "MARKING_STATUS"
                        {
                            if (alreadyinitialized)
                            {
                                _Current_Command = "TRIGGER_STATUS";
                                result.Success = SendCommandReadCellValue("G003");

                                if (result.Success)
                                {
                                    if (_Received_Data[0] == "1.000")
                                    {
                                        result.Result = true;
                                    }
                                    else
                                    {
                                        result.Result = false;
                                    }
                                }
                            }
                            //else
                            //{
                            //    result.Result = false;
                            //}                            
                        }
                        #endregion
                        break;
                    case "CONNECT_STATUS":
                        #region Command "CONNECT_STATUS"
                        {
                            if (alreadyinitialized)
                            {
                                result.Result = true;
                                result.Success = true;
                            }
                            else
                            {
                                result.Result = false;
                                result.Success = true;
                            }
                            
                        }
                        #endregion
                        break;
                    case "GET_VAL":
                        #region Command "GET_VAL"
                        {
                            if (alreadyinitialized)
                            {
                                _Current_Command = "GET_VAL";
                                result.Success = SendCommandReadCellValue(parameters[0].ToString());
                                if (result.Success)
                                {
                                    if (_Received_Data.Length >=0 )
                                    {
                                        result.Result = _Received_Data[0];
                                    }
                                    else
                                    {
                                        result.Result = string.Empty;
                                    }
                                }
                                else
                                {
                                    result.Result = string.Empty;
                                }
                            }
                        }
                        #endregion
                        break;
                    case "SET_FILE":
                        #region Command "SET_FILE"
                        {
                            if (alreadyinitialized)
                            {
                                _Current_Command = "SET_FILE";
                                result.Success = SendCommandSetFile((string)parameters[0]);
                            }
                        }
                        #endregion
                        break;
                    case "GET_FILENAME":
                        #region Command "GET_FILENAME"
                        {
                            if (alreadyinitialized)
                            {
                                _Current_Command = "GET_FILENAME";
                                result.Success = SendCommandReadCurrentJob();
                                if (result.Success)
                                {
                                    if (_Received_Data.Length > 0)
                                    {
                                        result.Result = _Received_Data[0];

                                        RaiseEvent("GET_FILENAME", true, result.Result);
                                    }
                                    else
                                    {
                                        result.Result = string.Empty;
                                    }

                                    Logger.Write("Laser Driver get filename" + result.Result);            
                                }
                                else
                                {
                                    result.Result = string.Empty;
                                }


                            }
                        }
                        #endregion
                        break;
                    case "SET_INT":
                        #region Command "SET_INT"
                        {
                            if (alreadyinitialized)
                            {
                                _Current_Command = "SET_INT";
                                result.Success = SendCommandSetInt((string)parameters[0]);
                            }
                        }
                        #endregion
                        break;
                    case "WRITE":
                        #region Command "SET_STRING"
                        {
                            if (alreadyinitialized)
                            {
                                _Current_Command = "WRITE";
                                result.Success = SendCommand((string)parameters[0], "Response");
                            }
                        }
                        #endregion
                        break;
                    default:
                        break;
                }           
            }
            catch (Exception ex)
            {
                ExManager.HandleException(ex, "Policy");
                alreadyinitialized = false;
                RaiseEvent("DISCONNECT", true, null);
                if (hardwaredriver != null)
                    hardwaredriver.Close();
            }
            return result;
        }



        private void hardwaredriver_OnConnected(object sender, EventArgs e)
        {
            RaiseEvent("CONNECTED", true, null);
        }

        private void hardwaredriver_OnConnectClosed(object sender, EventArgs e)
        {
            alreadyinitialized = false;

            RaiseEvent("DISCONNECTED", true, null);
        }

        private void hardwaredriver_OnDataReceived(object sender, CameraArgsL e)
        {
            
            _Received_Data = null;
            if (e.Tag != _Current_Tag)
            {
                _CameraRequest_Result = false;
            }
            else
            {

                string data_str = e.Value;
                _Received_Data = new string[] { data_str };
                if ((_Received_Data != null) && (_Received_Data.Length > 0) && (e.Status==1))
                {
                    _CameraRequest_Result = true;
                }
                else
                {
                    _CameraRequest_Result = false;
                }
            }

            _Signal_Command_Finished.Set();

            //RaiseEvent("DATA_RECEIVED", _CameraRequest_Result, _Received_Data);
        }

        public bool SendCommandSetFile(string file)
        {
            return SendCommand("LF" + file, "Response");
        }

        

        public bool SendCommandReadCellValue(string cell)
        {
            return SendCommand("GV" + cell, "CellOutput");
        }

        public bool SendCommandReadCurrentJob()
        {
            return SendCommand("GF", "FileName");
        }

        public bool SendCommandTrigger()
        {
            return SendCommand("SE8", "Response");
        }


        public bool SendCommandReset(string cmd)
        {
            return SendCommand(cmd , "Response");
        }

        public bool SendCommandSetInt(string value)
        {
            return SendCommand("SI" + value, "Response");
        }

        public bool SendCommandSetString(string value)
        {
            //return SendCommand("SS" + value, "Response");
            return hardwaredriver.SendCommand("SS"+value, "Response");
        }

        public bool SendCommandOnline(string onoff)
        {
            return SendCommand("SO " + onoff, "Response");
        }

        public bool SendCommandLaserStatus()
        {
            return true;// SendCommand(20261, string.Empty);//hardwaredriver.SendCommand(20261, string.Empty);
        }

        


        public bool SendCommand(string cmd,string tag)
        {
            bool ret = false;

            _Current_Tag = tag;
            cmd = cmd + "\r\n";

            ret = hardwaredriver.SendCommand(cmd, tag);

            if (ret)
            {
                ret = (_Signal_Command_Finished.WaitOne(2000, false)) && _CameraRequest_Result;
            }

            return ret;
        }

        #region Variable, common for each hardware, hardware related

        private AutoResetEvent _Signal_Command_Finished = new AutoResetEvent(false);
        private string[] _Received_Data = null;
        private String _Current_Command = String.Empty;
        private String _Current_Tag = string.Empty;
        private bool _CameraRequest_Result = false;
        #endregion

        public void RaiseEvent(string command, bool status, object result)
        {
            StationEventArgs arg = new StationEventArgs(hardwareName, command, status, result);
            eventClient.RaiseEvent(hardwareEvent, arg);
        }
    }
}
